home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Skunkware 98
/
Skunkware 98.iso
/
src
/
interp
/
tclStruct1.2.tar.gz
/
tclStruct1.2.tar
/
tclStruct1.2
/
stTrace.c
< prev
next >
Wrap
C/C++ Source or Header
|
1995-10-17
|
12KB
|
429 lines
/*
* tclStruct package
* Support 'C' structures in Tcl
*
* Written by Matthew Costello
* (c) 1995 AT&T Global Information Solutions, Dayton Ohio USA
*
* See the file "license.terms" for information on usage and
* redistribution of this file, and for a DISCLAIMER OF ALL WARRANTIES.
*/
#include "stInternal.h"
STRUCT_SCCSID("@(#)tclStruct:stTrace.c 1.3 95/10/17")
/****************************************************************/
/*
* This is the 'main' tracing routine for the object. It allows
* access to the whole object, and also handles references to
* pieces of the object (which are themselves objects).
*/
static CONST char *struct_last_trace_error;
char *
Struct_MainTraceProc(cdata, interp,name1,name2,flags)
ClientData cdata;
Tcl_Interp *interp;
char *name1,*name2;
int flags;
{
Struct_Object *object = (Struct_Object *)cdata;
Struct_Object thisobj;
CONST char *errstr;
if (object == NULL) {
return "Null pointer for object data in trace!";
}
#ifdef DEBUG
if (struct_debug & (DBG_PARSEELEMENT)) {
printf("Struct_MainTraceProc( %s(%s), f = %03o )\n",
name1,name2 ? name2 : "<null>",flags);
printf("\tdata=%p, type=%s, size=%d\n",
object->data,
Struct_TypeName(object->type),
object->size );
}
#endif
/* If the whole object is being deleted, then de-allocate
* the object and return.
*/
if (flags & TCL_TRACE_DESTROYED) {
Struct_DeleteObject(object);
return NULL;
}
/* The first thing to do is figure out what 'name2'
* (if present) points to. This 'thing' will also be
* an object.
*/
thisobj = *object;
Struct_AttachType(thisobj.type);
if ((errstr = Struct_AccessElement( interp, &thisobj, name2 )) != NULL) {
Struct_ReleaseType(thisobj.type);
return (char *)errstr;
}
/* Now call the correct tracing routine for the piece
* of the object.
*/
#ifdef TCL_MEM_DEBUG
Tcl_ValidateAllMemory(__FILE__,__LINE__);
#endif
if (thisobj.type->TraceProc == NULL) {
#ifdef DEBUG
if (struct_debug & (DBG_PARSEELEMENT))
printf("\tdata=%p, type=%s, size=%d\n",
object->data,
Struct_TypeName(object->type),
object->size );
#endif
Struct_ReleaseType(thisobj.type);
return "NULL TraceProc for object!";
}
{
ClientData cdata;
if ((cdata = Struct_GetClientData(interp)) != NULL) {
if (flags & TCL_TRACE_READS)
Struct_PkgInfo(cdata,si_rdCount) += 1;
else if (flags & TCL_TRACE_WRITES)
Struct_PkgInfo(cdata,si_wrCount) += 1;
}
}
errstr = (*thisobj.type->TraceProc)(&thisobj,interp,name1,name2,flags);
if (errstr != NULL)
struct_last_trace_error = errstr; /* save for TraceStruct, et. al. */
Struct_ReleaseType(thisobj.type);
#ifdef TCL_MEM_DEBUG
Tcl_ValidateAllMemory(__FILE__,__LINE__);
#endif
return (char *)errstr; /* Either NULL(good) or an error string */
}
/* I/O Pointer Trace */
char *
Struct_TracePtr(cdata, interp,name1,name2,flags)
ClientData cdata;
Tcl_Interp *interp;
char *name1,*name2;
int flags;
{
Struct_Object *object = (Struct_Object *)cdata;
static char ptrbuf[80];
if (!(object->type->flags & STRUCT_FLAG_IS_POINTER))
return "non-pointer type in Struct_TracePtr";
if (flags & TCL_TRACE_READS) {
int v;
/* Read a ptr : */
memcpy(&v,object->data,sizeof(v)); /* avoid bus error for misalignment */
if (object->type->u.a.array_elem->name == NULL)
sprintf(ptrbuf,"%d",v);
else if (v == 0)
strcpy(ptrbuf,"0");
else
sprintf(ptrbuf,"%.64s#%d",object->type->u.a.array_elem->name, v );
Tcl_SetVar2(interp,name1,name2,ptrbuf,flags&TCL_GLOBAL_ONLY);
} else if (flags & TCL_TRACE_WRITES) {
char *v;
char *s;
Struct_Object objbuf;
/* Write a ptr : illegal, make it read-only : */
if (object->type->u.a.array_elem->name == NULL)
return "can't change anonymous pointers";
if ((s = Tcl_GetVar2(interp,name1,name2,flags&TCL_GLOBAL_ONLY)) == NULL)
return "null ptr in ptr write";
if (strcmp(s,"0") == 0) {
v = NULL;
memcpy(object->data,&v,sizeof(v)); /* avoid bus error for misalignment */
return NULL;
}
if (Struct_GetObject(interp,s,&objbuf) == TCL_ERROR)
return "not a valid object or pointer";
v = (char *)objbuf.data;
if (objbuf.type != object->type->u.a.array_elem) {
Struct_ReleaseType(objbuf.type);
return "type mismatch in pointer write(o)";
}
Struct_ReleaseType(objbuf.type);
memcpy(object->data,&v,sizeof(v)); /* avoid bus error for misalignment */
return NULL;
} else {
/* Unset : */
#ifdef DEBUG
printf("\tunset!\n");
#endif
Struct_DeleteObject(object);
}
return NULL;
}
/* I/O Address Trace */
char *
Struct_TraceAddr(cdata, interp,name1,name2,flags)
ClientData cdata;
Tcl_Interp *interp;
char *name1,*name2;
int flags;
{
Struct_Object *object = (Struct_Object *)cdata;
static char ptrbuf[80];
if (!(object->type->flags & STRUCT_FLAG_IS_ADDR))
return "non-address type in Struct_TraceAddr";
if (flags & TCL_TRACE_READS) {
/* Read the data's address (in the form of a pointer) */
if (object->data == NULL)
strcpy(ptrbuf,"0");
else if (object->type->u.a.array_elem->name == NULL)
sprintf(ptrbuf,"%ld", (long)object->data);
else
sprintf(ptrbuf,"%.64s#%ld",object->type->u.a.array_elem->name,
(long)object->data );
Tcl_SetVar2(interp,name1,name2,ptrbuf,flags&TCL_GLOBAL_ONLY);
} else if (flags & TCL_TRACE_WRITES) {
/* Change the address of data: illegal, make it read-only : */
return "cannot change an object's address";
} else {
/* Unset : */
#ifdef DEBUG
printf("\tunset!\n");
#endif
Struct_DeleteObject(object);
}
return NULL;
}
/* I/O Structure Trace
* Convert to a list of files in the structure.
*/
char *
Struct_TraceStruct(cdata, interp,name1,name2,flags)
ClientData cdata;
Tcl_Interp *interp;
char *name1,*name2;
int flags;
{
Struct_Object *object = (Struct_Object *)cdata;
char namebuf[256];
char *p;
char *s;
Struct_StructElem *pelem;
if (!(object->type->flags & STRUCT_FLAG_IS_STRUCT))
return "non-struct type in Struct_TraceStruct";
#ifdef DEBUG
if (struct_debug & (DBG_PARSEELEMENT)) {
printf("Struct_TraceStruct( %s(%s), f = %03o )\n",
name1,name2 ? name2 : "",flags);
printf("\tdata=%p, type=%s, size=%d\n",
object->data,
Struct_TypeName(object->type),
object->size );
}
#endif
/* Get the name buffer ready for accessing the individual
* of the structure.
*/
if (name2 == NULL || *name2 == '\0') {
namebuf[0] = '\0';
p = namebuf;
} else {
strcpy( namebuf, name2 );
p = strchr( namebuf, '\0' );
*p++ = '.';
}
if (flags & TCL_TRACE_READS) {
Tcl_DString result;
Tcl_DStringInit(&result);
/* Tcl_DStringStartSublist(&result); */
for ( pelem = object->type->u.s.struct_def; pelem->type != NULL; pelem++ ) {
/* Build the proper name. */
strcpy( p, pelem->name );
#ifdef FOR_INFO_ONLY
objbuf.data = (char *)object->data + pelem->offset;
objbuf.type = pelem->type;
objbuf.size = pelem->type->size;
#endif
/* Now read the value ourselves. */
s = Tcl_GetVar2(interp,name1,namebuf,flags&TCL_GLOBAL_ONLY);
if (s == NULL) {
static Tcl_DString errbuf;
bad_element:
Tcl_DStringFree(&errbuf);
Tcl_DStringAppend(&errbuf,"structure element \"",-1);
Tcl_DStringAppend(&errbuf,namebuf,-1);
Tcl_DStringAppend(&errbuf,"\": ",-1);
Tcl_DStringAppend(&errbuf,(char *)struct_last_trace_error,-1);
return Tcl_DStringValue(&errbuf);
}
Tcl_DStringAppendElement(&result,s);
}
/* Tcl_DStringEndSublist(&result); */
Tcl_SetVar2(interp,name1,name2,Tcl_DStringValue(&result),flags&TCL_GLOBAL_ONLY);
Tcl_DStringFree(&result);
} else if (flags & TCL_TRACE_WRITES) {
/* Write a structure: */
int argc;
char **argv;
int i;
if ((s = Tcl_GetVar2(interp,name1,name2,flags&TCL_GLOBAL_ONLY)) == NULL)
return "null ptr in struct write";
#ifdef DEBUG
if (struct_debug & (DBG_ARRAY))
printf("Struct_TraceStruct: Write struct %s with {%s}\n",
Struct_TypeName(object->type), s );
#endif
if (Tcl_SplitList(interp,s,&argc,&argv) == TCL_ERROR)
return NULL;
if (argc > object->type->u.s.num_elements)
return "too many fields for structure";
for ( i = 0, pelem = object->type->u.s.struct_def; i < argc; i++, pelem++ ) {
/* Build the proper name. */
strcpy( p, pelem->name );
#ifdef FOR_INFO_ONLY
objbuf.data = (char *)object->data + pelem->offset;
objbuf.type = pelem->type;
objbuf.size = pelem->type->size;
#endif
/* Now set the the individual value. */
s = Tcl_SetVar2(interp,name1,namebuf,argv[i],flags&TCL_GLOBAL_ONLY);
if (s == NULL)
goto bad_element;
}
ckfree((char *)argv);
} else {
/* Unset : */
#ifdef DEBUG
printf("\tunset!\n");
#endif
Struct_DeleteObject(object);
}
return NULL;
}
/* I/O Array Trace
* This trace routine converts arrays too and from lists of elements.
*
* Note: Character and Hex arrays are traced by the TraceChar and TraceHex routines
*/
char *
Struct_TraceArray(cdata, interp,name1,name2,flags)
ClientData cdata;
Tcl_Interp *interp;
char *name1,*name2;
int flags;
{
Struct_Object *object = (Struct_Object *)cdata;
char namebuf[256];
char *p;
char *s;
if (!(object->type->flags & STRUCT_FLAG_IS_ARRAY))
return "non-array type in Struct_TraceArray";
#ifdef DEBUG
if (struct_debug & (DBG_PARSEELEMENT)) {
printf("Struct_TraceStruct( %s(%s), f = %03o )\n",
name1,name2 ? name2 : "",flags);
printf("\tdata=%p, type=%s, size=%d\n",
object->data,
Struct_TypeName(object->type),
object->size );
}
#endif
/* Get the name buffer ready for accessing the individual
* items of the array.
*/
if (name2 == NULL || *name2 == '\0') {
namebuf[0] = '\0';
p = namebuf;
} else {
strcpy( namebuf, name2 );
p = strchr( namebuf, '\0' );
*p++ = '.';
}
if (flags & TCL_TRACE_READS) {
int i, nelem;
Tcl_DString result;
Tcl_DStringInit(&result);
/* Tcl_DStringStartSublist(&result); */
nelem = object->size / object->type->u.a.array_elem->size;
for ( i = 0; i < nelem; i++ ) {
/* Build the proper name. */
sprintf( p, "%d", i );
/* Now read the value ourselves. */
s = Tcl_GetVar2(interp,name1,namebuf,flags&TCL_GLOBAL_ONLY);
if (s == NULL) {
static Tcl_DString errbuf;
bad_element:
Tcl_DStringFree(&errbuf);
Tcl_DStringAppend(&errbuf,"array element \"",-1);
Tcl_DStringAppend(&errbuf,namebuf,-1);
Tcl_DStringAppend(&errbuf,"\": ",-1);
Tcl_DStringAppend(&errbuf,(char *)struct_last_trace_error,-1);
return Tcl_DStringValue(&errbuf);
}
Tcl_DStringAppendElement(&result,s);
}
/* Tcl_DStringEndSublist(&result); */
Tcl_SetVar2(interp,name1,name2,Tcl_DStringValue(&result),flags&TCL_GLOBAL_ONLY);
Tcl_DStringFree(&result);
} else if (flags & TCL_TRACE_WRITES) {
/* Write a structure: */
int argc;
char **argv;
int i;
int nelem;
if ((s = Tcl_GetVar2(interp,name1,name2,flags&TCL_GLOBAL_ONLY)) == NULL)
return "null ptr in struct write";
#ifdef DEBUG
if (struct_debug & (DBG_ARRAY))
printf("Struct_TraceArray: Write array %s with {%s}\n",
Struct_TypeName(object->type), s );
#endif
if (Tcl_SplitList(interp,s,&argc,&argv) == TCL_ERROR)
return NULL;
nelem = object->size / object->type->u.a.array_elem->size;
if (argc > nelem)
return "too many items for array";
else if ( (argc < nelem ) &&
(object->type->flags & STRUCT_FLAG_STRICT) )
return "too few items for array";
for ( i = 0; i < argc; i++ ) {
/* Build the proper name. */
sprintf( p, "%d", i );
/* Now set the the individual value. */
s = Tcl_SetVar2(interp,name1,namebuf,argv[i],flags&TCL_GLOBAL_ONLY);
if (s == NULL)
goto bad_element;
}
ckfree((char *)argv);
} else {
/* Unset : */
#ifdef DEBUG
printf("\tunset!\n");
#endif
Struct_DeleteObject(object);
}
return NULL;
}